<script setup lang="ts">
import { computed, ref, reactive, watch, h } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { buildUUID, cloneDeep } from '@vben/utils';
import { renderDict } from '#/utils/render';
import {
  Form,
  FormItem,
  Input,
  InputNumber,
  TimePicker,
  Select,
  Table,
  Button,
  Popconfirm,
  Space,
  message,
  Modal,
} from 'ant-design-vue';
import { useBeforeCloseDiff } from '#/utils/popup';
import type {
  MedicationConfigForm,
  PlanConfigVO,
  Medication,
} from '#/api/healthPlan/config/planConfig/model';
import {
  planConfigInfo,
  planConfigUpdate,
} from '#/api/healthPlan/config/planConfig';
import type { RuleObject } from 'ant-design-vue/es/form';
import { medicinesListAll } from '#/api/medicine/medicines';
import type { MedicinesVO } from '#/api/medicine/medicines/model';
import type { SelectValue } from 'ant-design-vue/es/select';
import { getDictOptions } from '#/utils/dict';
import type { MedTempForm, MedTempVO } from '#/api/medicine/medTemp/model';
import { medTempAdd, medTempAll } from '#/api/medicine/medTemp';

const emit = defineEmits<{ reload: [] }>();

const title = '用药提醒配置';
const taskData = ref<PlanConfigVO | null>(null);

// --- 表单数据 ---
const getDefaultValues = (): Partial<MedicationConfigForm> => ({
  reminderName: undefined,
  templateId: undefined,
  intervalDays: 1,
  repeatCount: 1,
  startDate: undefined,
  endDate: undefined,
  reminderTimes: [''],
  medications: [],
});

const formData = ref<MedicationConfigForm>(getDefaultValues());

// --- 动态表格数据 ---
const editableData: Record<string, Medication> = reactive({});
const columns = [
  { title: '药品名称', dataIndex: 'medicationName', width: '30%' },
  { title: '用药剂量', dataIndex: 'dosage', width: '30%' },
  { title: '用药频次', dataIndex: 'frequency', width: '20%' },
  { title: '操作', dataIndex: 'operation' },
];

const validateReminderTimes = async (_rule: RuleObject, value: string[]) => {
  if (!value || value.length === 0) {
    return Promise.reject('请至少设置一个提醒时间');
  }
  if (value.some((time) => !time)) {
    return Promise.reject('所有提醒时间都必须填写');
  }
  return Promise.resolve();
};

const formRules = computed<
  Partial<Record<keyof MedicationConfigForm, RuleObject[]>>
>(() => {
  return {
    reminderName: [{ required: true, message: '请输入方案名称' }],
    intervalDays: [{ required: true, message: '请输入发送间隔天数' }],
    repeatCount: [{ required: true, message: '请输入发送次数' }],
    startDate: [{ required: true, message: '请输入开始时间' }],
    endDate: [{ required: true, message: '请输入结束时间' }],
    reminderTimes: [{ required: true, validator: validateReminderTimes }],
    medications: [
      { type: 'array', required: true, min: 1, message: '请至少添加一种药品' },
    ],
  };
});

const { validate, validateInfos, resetFields } = Form.useForm(
  formData,
  formRules,
);

// --- 远程搜索药品 ---
const fetching = ref(false);
const drugOptions = ref<MedicinesVO[]>([]);
const searchDrugsApi = async (keyword: string) => {
  const data = { tradeName: keyword };
  const medList = await medicinesListAll(data);
  return medList;
};

const handleDrugSearch = async (value: string) => {
  if (value) {
    fetching.value = true;
    drugOptions.value = await searchDrugsApi(value);
    fetching.value = false;
  } else {
    drugOptions.value = [];
  }
};

const handleDrugChange = (
  value: SelectValue,
  option: any,
  recordKey: string | number,
) => {
  if (option) {
    editableData[recordKey]!.medicationName = option.tradeName;
    editableData[recordKey]!.medicationId = option.id;
  }
};

// --- 表格操作 ---
const getRecordKey = (record: Medication) => record.id || record.tempId!;

const edit = (record: Medication) => {
  const key = getRecordKey(record);
  editableData[key] = cloneDeep(record);
};

// 保存药品行编辑
const save = (record: Medication) => {
  const key = getRecordKey(record);
  const target = formData.value.medications!.find(
    (item) => getRecordKey(item) === key,
  )!;
  Object.assign(target, editableData[key]);
  delete editableData[key];
};

// 取消药品行编辑
const cancel = (record: Medication) => {
  const key = getRecordKey(record);
  delete editableData[key];
  // 如果是取消一个新建的行，则直接从数据源中移除它
  if (record.tempId) {
    formData.value.medications = formData.value.medications!.filter(
      (item: Medication) => getRecordKey(item) !== key,
    );
  }
};
const handleAddMedication = () => {
  const newMed: Medication = {
    tempId: buildUUID(),
    medicationId: '',
    medicationName: '',
    dosageValue: undefined,
    dosageUnit: undefined,
    frequency: '',
  };
  drugOptions.value = [];
  formData.value.medications!.push(newMed);
  edit(newMed);
};
const handleDeleteMedication = (record: Medication) => {
  const key = getRecordKey(record);
  formData.value.medications = formData.value.medications!.filter(
    (item) => getRecordKey(item) !== key,
  );
};

// --- 提醒时间点管理 ---
watch(
  () => formData.value.repeatCount,
  (newCount) => {
    if (typeof newCount !== 'number' || newCount < 1) {
      formData.value.reminderTimes = [];
      return;
    }
    const currentTimes = formData.value.reminderTimes || [];
    const newTimes: string[] = new Array(newCount);
    for (let i = 0; i < newCount; i++) {
      newTimes[i] = currentTimes[i] || '';
    }
    formData.value.reminderTimes = newTimes;
  },
);

const medTempOptions = ref<MedTempVO[]>([]);
// 获取模板列表
const getMedTempOptions = async () => {
  medTempOptions.value = await medTempAll();
};
// 模板选择
const templateChange = (value: SelectValue) => {
  if (!value) {
    // 如果是清空操作，则不执行任何操作
    return;
  }

  // 如果当前已有药品，则弹出确认框
  if (formData.value.medications && formData.value.medications.length > 0) {
    Modal.confirm({
      title: '确认切换模板？',
      content: '切换模板将会覆盖当前已添加的药品列表，确定要继续吗？',
      okText: '确认切换',
      cancelText: '取消',
      onOk: () => {
        applyTemplate(value);
      },
      onCancel: () => {
        // 用户取消，将下拉框的值恢复为之前的值
        formData.value.templateId = taskData.value?.taskConfig?.templateId;
      },
    });
  } else {
    // 如果当前没有药品，则直接应用模板
    applyTemplate(value);
  }
};

const applyTemplate = (templateId: SelectValue) => {
  const selectedTemplate = medTempOptions.value.find(
    (template) => template.id === templateId,
  );
  if (selectedTemplate) {
    formData.value.medications = cloneDeep(selectedTemplate.medications);
    formData.value.templateId = templateId as string;
  }
};

// --- 弹窗逻辑 ---
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
  {
    initializedGetter: () => JSON.stringify(formData.value),
    currentGetter: () => JSON.stringify(formData.value),
  },
);

const [BasicModal, modalApi] = useVbenModal({
  class: 'w-[1000px]',
  onBeforeClose,
  onClosed: handleClosed,
  onConfirm: handleConfirm,
  onOpenChange: async (isOpen) => {
    if (!isOpen) return;
    modalApi.modalLoading(true);
    Promise.all([getMedTempOptions()]);
    const record = modalApi.getData() as PlanConfigVO;
    taskData.value = await planConfigInfo(record.id);
    if (taskData.value && taskData.value.taskConfig) {
      const config = taskData.value.taskConfig;
      formData.value = { ...getDefaultValues(), ...config };
    }
    await markInitialized();
    modalApi.modalLoading(false);
  },
});

// 保存用药模板
const saveMedicationTemplate = async (data: MedTempForm) => {
  return await medTempAdd(data);
};

const handleSaveAsTemplate = () => {
  if (!formData.value.medications || formData.value.medications.length === 0) {
    message.warning('药品列表为空，无法保存为模板');
    return;
  }

  const newTemplateName = ref('');
  Modal.confirm({
    title: '保存为新模板',
    content: () =>
      h('div', [
        h('p', { class: 'mb-2' }, '请输入新模板的名称，以便将来复用。'),
        h(Input, {
          placeholder: '请输入新模板的名称',
          value: newTemplateName.value,
          onInput: (e: Event) => {
            newTemplateName.value = (e.target as HTMLInputElement).value;
          },
        }),
      ]),
    async onOk() {
      if (!newTemplateName.value) {
        message.error('模板名称不能为空');
        return Promise.reject();
      }
      const templateData = {
        medications: formData.value.medications,
        templateName: newTemplateName.value,
      };
      const newTemplateId = await saveMedicationTemplate(templateData);
      message.success('模板保存成功');
      // 刷新模板列表
      await getMedTempOptions();
      // 自动选中新创建的模板
      formData.value.templateId = newTemplateId;
    },
  });
};

async function handleConfirm() {
  if (Object.keys(editableData).length > 0) {
    message.warning('您有正在编辑的药品尚未保存，请先保存或取消编辑');
    return;
  }

  try {
    modalApi.modalLoading(true);
    await validate();
    const data = cloneDeep(formData.value);

    // 提交前，清理前端临时ID
    data.medications?.forEach((med) => {
      if (med.tempId) {
        med.id = med.tempId;
      }
    });

    const submitData = {
      ...taskData.value,
      taskConfig: data,
      triggerConfig: {
        // 每日触发
        dailyTrigger: true,
      },
    };

    await planConfigUpdate(submitData);
    resetAndClose();
  } catch (error) {
    console.error(error);
  } finally {
    modalApi.modalLoading(false);
  }
}

function resetAndClose() {
  resetInitialized();
  emit('reload');
  modalApi.close();
}

function handleClosed() {
  resetFields();
  formData.value = getDefaultValues();
  Object.keys(editableData).forEach((key) => delete editableData[key]);
  resetInitialized();
}
</script>

<template>
  <BasicModal :title="title">
    <Form :model="formData" :label-col="{ span: 4 }">
      <FormItem label="方案名称" v-bind="validateInfos.reminderName">
        <Input v-model:value="formData.reminderName" />
      </FormItem>
      <FormItem label="用药模板">
        <Select
          v-model:value="formData.templateId"
          :options="medTempOptions"
          :fieldNames="{ label: 'templateName', value: 'id' }"
          @change="templateChange"
          placeholder="请选择用药模板"
          allow-clear
        />
      </FormItem>
      <FormItem label="发送方式" required>
        <Space>
          <FormItem v-bind="validateInfos.intervalDays" class="!mb-0">
            <InputNumber
              v-model:value="formData.intervalDays"
              :min="1"
              addon-before="每"
              addon-after="天"
            />
          </FormItem>
          <FormItem v-bind="validateInfos.repeatCount" class="!mb-0">
            <InputNumber
              v-model:value="formData.repeatCount"
              :min="1"
              addon-before="发送"
              addon-after="次"
            />
          </FormItem>
        </Space>
      </FormItem>
      <FormItem label="开始时间" v-bind="validateInfos.startDate">
        <InputNumber
          v-model:value="formData.startDate"
          addon-before="周期内第"
          addon-after="天"
          :min="1"
        />
      </FormItem>
      <FormItem label="结束时间" v-bind="validateInfos.endDate">
        <InputNumber
          v-model:value="formData.endDate"
          addon-before="周期内第"
          addon-after="天"
          :min="1"
        />
      </FormItem>
      <FormItem label="提醒时间" v-bind="validateInfos.reminderTimes">
        <Space direction="vertical" class="w-full">
          <Space
            v-for="(time, index) in formData.reminderTimes"
            :key="index"
            align="baseline"
          >
            <TimePicker
              v-model:value="formData.reminderTimes![index]"
              class="w-full"
              format="HH:mm:ss"
              value-format="HH:mm:ss"
            />
          </Space>
        </Space>
      </FormItem>
      <FormItem label="用药内容" v-bind="validateInfos.medications">
        <Table
          :columns="columns"
          :data-source="formData.medications"
          :pagination="false"
          bordered
          :row-key="(record) => record.id || record.tempId"
        >
          <template #title>
            <div class="flex justify-end">
              <Button size="small" @click="handleSaveAsTemplate"
                >保存为模板</Button
              >
            </div>
          </template>
          <template #bodyCell="{ column, text, record }">
            <template v-if="column.dataIndex === 'medicationName'">
              <div v-if="editableData[getRecordKey(record)]">
                <Select
                  v-model:value="
                    editableData[getRecordKey(record)]!.medicationName
                  "
                  show-search
                  placeholder="请输入并搜索药品"
                  :options="drugOptions"
                  :filter-option="false"
                  :not-found-content="fetching ? null : undefined"
                  :fieldNames="{ label: 'tradeName', value: 'id' }"
                  @search="handleDrugSearch"
                  @change="
                    (value, option) =>
                      handleDrugChange(value, option, getRecordKey(record))
                  "
                />
              </div>
              <template v-else>
                {{ text }}
              </template>
            </template>
            <template v-else-if="column.dataIndex === 'dosage'">
              <div v-if="editableData[getRecordKey(record)]">
                <Space.Compact>
                  <InputNumber
                    v-model:value="
                      editableData[getRecordKey(record)]!.dosageValue
                    "
                    :min="0"
                    placeholder="请输入剂量"
                    class="w-[140px]"
                  />
                  <Select
                    v-model:value="
                      editableData[getRecordKey(record)]!.dosageUnit
                    "
                    :options="getDictOptions('med_dosage_unit')"
                    placeholder="单位"
                    class="w-[80px]"
                  />
                </Space.Compact>
              </div>
              <template v-else>
                <div class="flex items-center">
                  {{ record.dosageValue }}
                  <component
                    :is="renderDict(record.dosageUnit, 'med_dosage_unit')"
                  />
                </div>
              </template>
            </template>
            <template v-else-if="column.dataIndex === 'frequency'">
              <div v-if="editableData[getRecordKey(record)]">
                <Select
                  v-model:value="editableData[getRecordKey(record)]!.frequency"
                  :options="getDictOptions('med_frequency_type')"
                  placeholder="请选择频次"
                />
              </div>
              <template v-else>
                <component
                  :is="renderDict(record.frequency, 'med_frequency_type')"
                />
              </template>
            </template>
            <template v-else-if="column.dataIndex === 'operation'">
              <div class="editable-row-operations">
                <span v-if="editableData[getRecordKey(record)]">
                  <Button
                    type="link"
                    @click="save(record)"
                    style="padding-left: 0"
                    >保存</Button
                  >
                  <Popconfirm title="确定取消吗?" @confirm="cancel(record)">
                    <Button type="link">取消</Button>
                  </Popconfirm>
                </span>
                <span v-else>
                  <Button
                    type="link"
                    @click="edit(record)"
                    style="padding-left: 0"
                    >编辑</Button
                  >
                  <Popconfirm
                    title="确定删除吗?"
                    @confirm="handleDeleteMedication(record)"
                  >
                    <Button type="link" danger>删除</Button>
                  </Popconfirm>
                </span>
              </div>
            </template>
          </template>
          <template #footer>
            <Button @click="handleAddMedication" type="dashed" block
              >+ 添加药品</Button
            >
          </template>
        </Table>
      </FormItem>
    </Form>
  </BasicModal>
</template>
